head_line = '''//------------------------------------------------------------
//  Filename: {}.sv
//   
//  Author  : wlduan@ucchip.com
//  Revise  : 2019-10-16 15:51
//  Description: 
//   
//  Copyright (C) 2019, UCCHIP, Inc. 					      
//  All Rights Reserved.                                       
//-------------------------------------------------------------
//
'''
 
import os

class generic_module():
    fp = ""
    name = ""
    parameters = []
    input_port = []
    outputport = []
    bus__ports = []
    comb_block = []
    seqs_block = []
    inner_inst = []

    def add_inports(self, sig_type, sig_name):
        self.input_port.append("input " + sig_type + " " + sig_name)

    def add_bus(self, bus_type, bus_name):
        self.bus__ports.append(bus_type + " " + bus_name)

    def add_param(self, param_name, param_val):
        self.parameters.append(param_name + " = " + param_val)

    def __init__(self,name="generic"):
        self.name = name 
        if not os.path.exists("./rtl"):
            os.mkdir("./rtl")
        if not os.path.exists("./sim"):
            os.mkdirs("./sim")    
        #os.system("mkdir ./rtl")
    
    def add_seqs(self,clk,rstn,sig_a,sig_b):
        seq_str = ''' 
        always_ff@(posedge {},negedge {}) begin
            if({} == 1'b0) begin
                {} <= 'b0
            end
            else begin
                {} <= {}
            end
        end
        '''.format(clk,rstn,rstn,sig_a,sig_a,sig_b)
        self.fp.write(seq_str)

    def add_assign(self,sig_a,sig_b):
        self.fp.write("assign {} = {}; \n".format(sig_a,sig_b))

    def add_comb(self,sig_a,sig_b):
        self.fp.write("always_comb {} = {}; \n".format(sig_a,sig_b))

    def gen_param_def_code(self):
        if self.parameters:
            self.fp.write(" #(\n".format(self.name))
            port_str = ""
            for param in self.parameters:
                port_str += ("\tparameter " + param + ",\n")
            if len(port_str) > 2 :
                self.fp.write(port_str[:len(port_str)-2])
            self.fp.write("\n)\n".format(self.name))

    def gen_port_def_code(self):
        self.fp.write("(\n")
        port_str = ""
        for in_def in self.input_port:
            port_str += ("\t" + in_def +  ",\n")
        port_str += "\n"    
        for out_def in self.outputport:
            port_str += ("\t" + out_def + ",\n")
        port_str += "\n"    
        for bus_def in self.bus__ports:
            port_str += ("\t" + bus_def + ",\n")
        if len(port_str) > 2 :
            self.fp.write(port_str[:len(port_str)-2])
        self.fp.write("\n);\n")

    def gen_module_body_code(self):
        pass

    def gen_module_head_code(self):
        self.fp.write("\n`timescale 1ns/1ps \n\n")
        self.fp.write("module {} ".format(self.name))

    def gen_module_end_code(self):
        self.fp.write("\nendmodule  ")

    def gen_module(self):
        with open("./rtl/{}.sv".format(self.name), 'w') as self.fp:
            self.fp.write(head_line.format(self.name))
            self.gen_module_head_code()
            self.gen_param_def_code()
            self.gen_port_def_code()
            self.gen_module_body_code()
            self.gen_module_end_code()
    
    tb_line0 = '''
    logic clk,rst_n;


    localparam CLK_PERIOD = 100;
    localparam RST_PERIOD = 10000;
    localparam SIM_TIME   = 1e7;

    initial begin
        clk = 0;
        rst_n = 0;
        forever #(CLK_PERIOD/2) clk = ~clk;
    end
    
    initial #(RST_PERIOD) rst_n = 1'b1;

    initial begin
        #(SIM_TIME) $finish();
    end

    //initial begin
    //    $fsdbDumpfile("wave.fsdb");
    //    $fsdbDumpvars();
    //    $fsdbDumpMDA();
    //end   

    '''
    
    tb_line1 = ""

    def gen_test_bench(self):
        with open("./sim/{}_tb.sv".format(self.name), 'w') as tb_fp:
            tb_fp.write(head_line.format(self.name+"_tb"))
            tb_fp.write("\n`timescale 1ns/1ps \n\n")
            tb_fp.write("module {}_tb(); \n\n".format(self.name))
            tb_fp.write(self.tb_line0)
            tb_fp.write(self.tb_line1)
            tb_fp.write("\nendmodule")

    def gen_test_line1(self):
        pass

    def gen_simulation_list(self):
        with open("./sim/rtl.f", 'w') as list_fp:
            for rtl_file in  os.listdir("./rtl"):
                ext = os.path.splitext(rtl_file)[1]
                if ext == ".sv":
                    list_fp.write("-sv ../rtl/{}\n".format(rtl_file))  


    def gen_simulation_env(self):
        self.gen_simulation_list()
        self.gen_test_line1()
        self.gen_test_bench()

if __name__ == '__main__':
    dut = generic_module("generic")
    dut.gen_module()
